diff options
Diffstat (limited to 'app/[lng]/test/table-v2/columns.tsx')
| -rw-r--r-- | app/[lng]/test/table-v2/columns.tsx | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/app/[lng]/test/table-v2/columns.tsx b/app/[lng]/test/table-v2/columns.tsx new file mode 100644 index 00000000..703e9fd8 --- /dev/null +++ b/app/[lng]/test/table-v2/columns.tsx @@ -0,0 +1,212 @@ +"use client"; + +import { ColumnDef } from "@tanstack/react-table"; +import { Badge } from "@/components/ui/badge"; +import { TestProduct } from "@/db/schema/test-table-v2"; +import { OrderWithDetails } from "./column-defs"; + +// === Product Columns (Pattern 1, 2) === +// meta.serverGroupable: 서버 사이드 GROUP BY 지원 여부 + +export const productColumns: ColumnDef<TestProduct>[] = [ + { + accessorKey: "id", + header: "ID", + size: 60, + enableGrouping: false, // 클라이언트 그룹핑도 비활성화 + meta: { serverGroupable: false }, + }, + { + accessorKey: "sku", + header: "SKU", + size: 100, + enableGrouping: false, + meta: { serverGroupable: false }, + }, + { + accessorKey: "name", + header: "Product Name", + size: 200, + enableGrouping: false, + meta: { serverGroupable: false }, + }, + { + accessorKey: "category", + header: "Category", + size: 120, + enableGrouping: true, // ✅ 그룹핑 가능 + meta: { serverGroupable: true }, + cell: ({ getValue }) => { + const category = getValue() as string; + return <Badge variant="outline">{category}</Badge>; + }, + }, + { + accessorKey: "price", + header: "Price", + size: 100, + enableGrouping: false, + meta: { serverGroupable: false }, + cell: ({ getValue }) => { + const price = parseFloat(getValue() as string); + return new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(price); + }, + }, + { + accessorKey: "stock", + header: "Stock", + size: 80, + enableGrouping: false, + meta: { serverGroupable: false }, + cell: ({ getValue }) => { + const stock = getValue() as number; + return ( + <span className={stock < 10 ? "text-red-500 font-medium" : ""}> + {stock} + </span> + ); + }, + }, + { + accessorKey: "status", + header: "Status", + size: 110, + enableGrouping: true, // ✅ 그룹핑 가능 + meta: { serverGroupable: true }, + cell: ({ getValue }) => { + const status = getValue() as string; + const variants: Record<string, "default" | "secondary" | "destructive"> = { + active: "default", + inactive: "secondary", + discontinued: "destructive", + }; + return <Badge variant={variants[status] || "secondary"}>{status}</Badge>; + }, + }, + { + accessorKey: "isNew", + header: "New", + size: 60, + enableGrouping: true, // ✅ 그룹핑 가능 + meta: { serverGroupable: true }, + cell: ({ getValue }) => { + const isNew = getValue() as boolean; + return isNew ? <Badge className="bg-emerald-500">NEW</Badge> : null; + }, + }, + { + accessorKey: "createdAt", + header: "Created", + size: 110, + enableGrouping: false, + meta: { serverGroupable: false }, + cell: ({ getValue }) => { + const date = getValue() as Date; + return date ? new Date(date).toLocaleDateString() : "-"; + }, + }, +]; + +// === Order Columns with joined data (Pattern 3 - Custom Service) === + +export const orderColumns: ColumnDef<OrderWithDetails>[] = [ + { + accessorKey: "id", + header: "ID", + size: 60, + }, + { + accessorKey: "orderNumber", + header: "Order #", + size: 140, + cell: ({ getValue }) => ( + <span className="font-mono text-xs">{getValue() as string}</span> + ), + }, + { + accessorKey: "customerName", + header: "Customer", + size: 150, + }, + { + accessorKey: "customerTier", + header: "Tier", + size: 90, + cell: ({ getValue }) => { + const tier = getValue() as string; + if (!tier) return "-"; + const colors: Record<string, string> = { + standard: "bg-gray-500", + premium: "bg-blue-500", + vip: "bg-amber-500", + }; + return ( + <Badge className={colors[tier] || "bg-gray-500"}> + {tier.toUpperCase()} + </Badge> + ); + }, + }, + { + accessorKey: "productName", + header: "Product", + size: 180, + }, + { + accessorKey: "quantity", + header: "Qty", + size: 60, + }, + { + accessorKey: "totalAmount", + header: "Total", + size: 100, + cell: ({ getValue }) => { + const amount = parseFloat(getValue() as string); + return new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(amount); + }, + }, + { + accessorKey: "status", + header: "Status", + size: 110, + cell: ({ getValue }) => { + const status = getValue() as string; + const variants: Record<string, "default" | "secondary" | "destructive" | "outline"> = { + pending: "outline", + processing: "secondary", + shipped: "default", + delivered: "default", + cancelled: "destructive", + }; + const colors: Record<string, string> = { + delivered: "bg-emerald-500", + shipped: "bg-blue-500", + }; + return ( + <Badge + variant={variants[status] || "secondary"} + className={colors[status] || ""} + > + {status} + </Badge> + ); + }, + }, + { + accessorKey: "orderedAt", + header: "Order Date", + size: 110, + cell: ({ getValue }) => { + const date = getValue() as Date; + return date ? new Date(date).toLocaleDateString() : "-"; + }, + }, +]; + |
